package com.todo.content.application.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.todo.common.common.constants.BizConstants;
import com.todo.common.common.entity.response.page.PageResult;
import com.todo.common.common.enums.AllowedCommentEnum;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.common.common.enums.biz.PrivateTypeEnum;
import com.todo.common.common.exception.BizException;
import com.todo.component.redis.RedisService;
import com.todo.content.application.convert.ContentConvert;
import com.todo.content.application.entity.bo.ContentDetailBO;
import com.todo.content.application.entity.bo.ContentInfoBO;
import com.todo.content.application.entity.bo.ContentInfoCountBO;
import com.todo.content.application.entity.condition.ContentInfoConditionBO;
import com.todo.content.application.mq.entity.ContentStatusChangeEntity;
import com.todo.content.application.mq.send.ContentMqSender;
import com.todo.content.application.service.ContentInfoService;
import com.todo.content.common.base.ContentKeyBuild;
import com.todo.content.common.enums.ContentStatusEnum;
import com.todo.content.infrastructure.entity.condition.ContentInfoCondition;
import com.todo.content.infrastructure.entity.domain.ContentDetailDO;
import com.todo.content.infrastructure.entity.po.ContentInfoPO;
import com.todo.content.infrastructure.helper.es.entity.ContentDetailEntity;
import com.todo.content.infrastructure.helper.es.mapper.ContentDetailEntityMapper;
import com.todo.content.infrastructure.repository.ContentInfoRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.dromara.easyes.core.conditions.update.LambdaEsUpdateWrapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (ContentInfo)表服务实现类
 *
 * @author zhangwenxiang
 * @since 2024-03-04 00:19:45
 */
@Slf4j
@Service("contentInfoService")
public class ContentInfoServiceImpl implements ContentInfoService {

    @Value("${content.default.examine:false}")
    private Boolean defaultExamine;


    @Resource
    private ContentInfoRepository contentInfoRepository;
    @Resource
    private RedisService redisService;
    @Resource
    private ContentDetailEntityMapper contentDetailEntityMapper;
    @Resource
    private ContentMqSender contentMqSender;

    @Override
    public Long insertContentDetail(ContentDetailBO contentDetailBO) {
        if (contentDetailBO == null || contentDetailBO.getContentInfoBO() == null) {
            return null;
        }
        //前置校验
        ContentDetailBO alreadyContentDetailBO = queryContentDetailById(contentDetailBO.getContentInfoBO().getId());
        if (alreadyContentDetailBO != null) {
            log.warn("ContentInfoService#insertContentDetail 保存内容信息前置校验失败，保存操作存在数据，无法新增 contentDetailBO：【{}】", JSONObject.toJSONString(contentDetailBO));
            return null;
        }
        ContentInfoBO contentInfoBO = contentDetailBO.getContentInfoBO();
        if (contentInfoBO.getExtra() != null && CollectionUtils.isNotEmpty(contentInfoBO.getExtra().getRelationImgList())) {
            List<String> relationImgList = contentInfoBO.getExtra().getRelationImgList();
            if (relationImgList.size() > BizConstants.DEFAULT_MAX_RELATION_IMG_SIZE) {
                log.error("ContentInfoService#insertContentDetail 新增内容前置校验失败 超过默认支持图片数量 contentDetailBO：【{}】", JSONObject.toJSONString(contentDetailBO));
                return null;
            }
        }

        //填充新增数据的默认数量
        contentDetailBO.getContentInfoBO().setStatus(ContentStatusEnum.POSTED);
        contentInfoBO.setSeeCount(0);
        contentInfoBO.setLikeCount(0);
        contentInfoBO.setCommentCount(0);
        contentInfoBO.setCollectCount(0);
        ContentDetailDO contentDetailDO = ContentConvert.convertToContentDetailDO(contentDetailBO);
        Boolean insertResult = contentInfoRepository.insertContentDetail(contentDetailDO);
        //保存成功情况下进行内容自动化审核
        if (insertResult) {
            if (!defaultExamine) {
                //不开启情况下直接走人工审核
                updateContentStatus(contentDetailDO.getId(), ContentStatusEnum.POSTED, ContentStatusEnum.AUTO_EXAMINE_FAILED);
            } else {
                doContentStatusChange(contentDetailDO.getId(), ContentStatusEnum.POSTED);
            }
            return contentDetailDO.getId();
        }
        return null;
    }


    @Override
    public Boolean updateContentDetail(ContentDetailBO contentDetailBO) {
        if (contentDetailBO == null || contentDetailBO.getContentInfoBO() == null) {
            return false;
        }
        ContentDetailBO alreadyContentDetailBO = queryContentDetailById(contentDetailBO.getContentInfoBO().getId());
        if (alreadyContentDetailBO == null) {
            log.warn("ContentInfoService#updateContentDetail 保存内容信息前置校验失败，更新操作不存在数据，无法更新 contentDetailBO：【{}】", JSONObject.toJSONString(contentDetailBO));
            return false;
        }
        ContentInfoBO contentInfoBO = contentDetailBO.getContentInfoBO();
        if (contentInfoBO.getExtra() != null && CollectionUtils.isNotEmpty(contentInfoBO.getExtra().getRelationImgList())) {
            List<String> relationImgList = contentInfoBO.getExtra().getRelationImgList();
            if (relationImgList.size() > BizConstants.DEFAULT_MAX_RELATION_IMG_SIZE) {
                log.error("ContentInfoService#updateContentDetail 更新内容详情失败 超过默认支持图片数量 contentDetailBO：【{}】", JSONObject.toJSONString(contentDetailBO));
                return false;
            }
        }

        contentDetailBO.getContentInfoBO().setStatus(ContentStatusEnum.POSTED);
        ContentDetailDO contentDetailDO = ContentConvert.convertToContentDetailDO(contentDetailBO);
        Boolean updateResult = contentInfoRepository.updateContentDetailById(contentDetailDO, false);
        if (updateResult) {
            //内容发生变更，需要重新进入审核阶段
            if (!alreadyContentDetailBO.getContentInfoBO().getContent().equals(contentDetailDO.getContentInfo().getContent()) && !defaultExamine) {
                //不开启情况下直接走人工审核
                updateContentStatus(contentInfoBO.getId(), ContentStatusEnum.POSTED, ContentStatusEnum.AUTO_EXAMINE_FAILED);
            } else {
                doContentStatusChange(contentInfoBO.getId(), ContentStatusEnum.POSTED);
            }
            String contentDetailKey = ContentKeyBuild.buildContentDetailKey(contentDetailBO.getContentInfoBO().getId());
            redisService.del(contentDetailKey);

            LambdaEsQueryWrapper<ContentDetailEntity> wrapper = new LambdaEsQueryWrapper<>();
            wrapper.eq(ContentDetailEntity::getMysqlId, contentDetailDO.getId());
            contentDetailEntityMapper.delete(wrapper);

        }
        return updateResult;
    }

    @Override
    public Boolean removeContentDetailById(Long contentId) {
        if (contentId == null || contentId < 0) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        ContentInfoPO contentInfoPO = contentInfoRepository.queryContentInfoPOById(contentId);
        if (contentInfoPO == null) {
            log.info("ContentInfoService#removeContentDetailById 删除内容详情，根据主键id查询数据为空 默认删除成功 contentId：【{}】", contentId);
            return true;
        }
        Boolean removeResult = contentInfoRepository.removeContentById(contentId);
        if (removeResult) {
            //删除对应缓存、ES数据等
            String contentDetailKey = ContentKeyBuild.buildContentDetailKey(contentId);
            redisService.del(contentDetailKey);
            LambdaEsQueryWrapper<ContentDetailEntity> wrapper = new LambdaEsQueryWrapper<>();
            wrapper.eq(ContentDetailEntity::getMysqlId, contentId);
            contentDetailEntityMapper.delete(wrapper);
        }
        return removeResult;
    }


    @Override
    public Boolean updateContentStatus(Long contentId, ContentStatusEnum oldStatus, ContentStatusEnum newStatus) {
        if (contentId == null || oldStatus == null || newStatus == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        if (oldStatus.equals(ContentStatusEnum.DISABLE)) {
            log.error("ContentInfoService#updateContentStatus 更新内容状态失败 已废弃的状态无法操作 contentId:{}", contentId);
            throw new BizException(BizErrorCodeEnum.CONTENT_STATUS_OPERATE_PROHIBITED);
        }
        ContentInfoPO contentInfoPO = contentInfoRepository.queryContentInfoPOById(contentId);
        if (contentInfoPO == null) {
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }
        if (!contentInfoPO.getStatus().equals(oldStatus.getType())) {
            log.info("ContentInfoService#updateContentStatus 更新内容状态失败 原状态与当前不一致，无需更新 contentId：【{}】", contentId);
            return false;
        }
        if (contentInfoPO.getStatus().equals(newStatus.getType())) {
            log.info("ContentInfoService#updateContentStatus 更新内容状态失败 原状态与当前一致，无需更新 contentId：【{}】", contentId);
            return true;
        }
        Boolean updateResult = contentInfoRepository.updateContentStatus(contentId, oldStatus.getType(), newStatus.getType());
        if (updateResult) {
            String contentDetailKey = ContentKeyBuild.buildContentDetailKey(contentId);
            redisService.del(contentDetailKey);
            doContentStatusChange(contentId, newStatus);
        }
        return updateResult;
    }

    @Override
    public Boolean modifyPrivateType(Long contentId, PrivateTypeEnum privateTypeEnum) {
        if (contentId == null || privateTypeEnum == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        ContentDetailBO contentDetailBO = queryContentDetailById(contentId);
        if (contentDetailBO == null) {
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }
        if (contentDetailBO.getContentInfoBO().getIsPrivate().equals(privateTypeEnum)) {
            log.info("ContentInfoService#modifyPrivateType 调整私有字段完成，私有类型与当前一致，无需更新 contentId：【{}】", contentId);
            return true;
        }

        Boolean updateResult = contentInfoRepository.updateContentPrivateType(contentId, privateTypeEnum.getType());
        if (updateResult) {
            //调整ES、Redis
            String detailKey = ContentKeyBuild.buildContentDetailKey(contentId);
            redisService.del(detailKey);
            LambdaEsUpdateWrapper<ContentDetailEntity> wrapper = new LambdaEsUpdateWrapper<>();
            wrapper.eq(ContentDetailEntity::getMysqlId, contentId);
            wrapper.set(ContentDetailEntity::getIsPrivate, privateTypeEnum.getType());
            contentDetailEntityMapper.update(null, wrapper);
        }
        return updateResult;
    }

    @Override
    public Boolean modifyCommitType(Long contentId, AllowedCommentEnum commentEnum) {
        if (contentId == null || commentEnum == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        ContentDetailBO contentDetailBO = queryContentDetailById(contentId);
        if (contentDetailBO == null) {
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }
        if (contentDetailBO.getContentInfoBO().getAllowComment().equals(commentEnum)) {
            log.info("ContentInfoService#modifyCommitType 调整评论字段完成，评论类型与当前一致，无需更新 contentId：【{}】", contentId);
            return true;
        }
        Boolean updateResult = contentInfoRepository.updateContentCommitType(contentId, commentEnum.getType());
        if (updateResult) {
            String detailKey = ContentKeyBuild.buildContentDetailKey(contentId);
            redisService.del(detailKey);
            LambdaEsUpdateWrapper<ContentDetailEntity> wrapper = new LambdaEsUpdateWrapper<>();
            wrapper.eq(ContentDetailEntity::getMysqlId, contentId);
            wrapper.set(ContentDetailEntity::getAllowComment, commentEnum.getType());
            contentDetailEntityMapper.update(null, wrapper);
        }
        return updateResult;
    }

    @Override
    public ContentDetailBO queryContentDetailById(Long contentId) {
        if (contentId == null || contentId < 0) {
            return null;
        }
        String contentDetailKey = ContentKeyBuild.buildContentDetailKey(contentId);
        if (redisService.hasKey(contentDetailKey)) {
            return JSONObject.parseObject(redisService.get(ContentKeyBuild.buildContentDetailKey(contentId)), ContentDetailBO.class);
        }
        ContentDetailDO contentDetailDO = contentInfoRepository.queryContentDetailById(contentId);
        if (contentDetailDO == null) {
            log.info("ContentInfoService#queryContentDetailById 根据主键查询详情信息完成，数据为空 contentId：【{}】", contentId);
            return null;
        }
        ContentDetailBO contentDetailBO = ContentConvert.convertToContentDetailBO(contentDetailDO);
        redisService.set8H(contentDetailKey, JSONObject.toJSONString(contentDetailBO));
        return contentDetailBO;
    }

    @Override
    public PageResult<ContentInfoBO> queryContentInfoByCondition(ContentInfoConditionBO conditionBO) {
        if (conditionBO == null) {
            return new PageResult<>();
        }
        ContentInfoCondition condition = ContentConvert.convertToContentInfoCondition(conditionBO);
        PageResult<ContentInfoPO> pageResult = contentInfoRepository.queryContentInfoByCondition(condition);
        if (pageResult == null) {
            return new PageResult<>();
        }
        PageResult<ContentInfoBO> result = new PageResult<>();
        result.setResults(pageResult.getResults() == null ? null : pageResult.getResults().stream().map(ContentConvert::convertToContentInfoBO).collect(Collectors.toList()));
        result.setTotal(pageResult.getTotal());
        result.setHasNext(pageResult.isHasNext());
        result.setPageNum(pageResult.getPageNum());
        result.setPageCount(pageResult.getPageCount());
        result.setCurrentIndex(pageResult.getCurrentIndex());
        result.setPageSize(pageResult.getPageSize());
        return result;
    }

    @Override
    public Boolean savePreCheck(ContentDetailBO contentDetailBO, Boolean isInsert) {
        if (contentDetailBO == null || contentDetailBO.getContentInfoBO() == null) {
            return false;
        }
        ContentDetailBO alreadyContentDetailBO = queryContentDetailById(contentDetailBO.getContentInfoBO().getId());
        if (isInsert) {
            if (alreadyContentDetailBO != null) {
                log.warn("ContentInfoService#savePreCheck 保存内容信息前置校验失败，保存操作存在数据，无法新增 contentDetailBO：【{}】", JSONObject.toJSONString(contentDetailBO));
                return false;
            }
            ContentInfoBO contentInfoBO = contentDetailBO.getContentInfoBO();
            if (contentInfoBO.getExtra() != null && CollectionUtils.isNotEmpty(contentInfoBO.getExtra().getRelationImgList())) {
                List<String> relationImgList = contentInfoBO.getExtra().getRelationImgList();
                if (relationImgList.size() > BizConstants.DEFAULT_MAX_RELATION_IMG_SIZE) {
                    log.error("ContentInfoService#savePreCheck 新增内容前置校验失败 超过默认支持图片数量 contentDetailBO：【{}】", JSONObject.toJSONString(contentDetailBO));
                    return false;
                }
            }
            return true;
        }
        if (alreadyContentDetailBO == null) {
            log.warn("ContentInfoService#savePreCheck 保存内容信息前置校验失败，更新操作不存在数据，无法更新 contentDetailBO：【{}】", JSONObject.toJSONString(contentDetailBO));
            return false;
        }
        ContentInfoBO contentInfoBO = contentDetailBO.getContentInfoBO();
        if (contentInfoBO.getExtra() != null && CollectionUtils.isNotEmpty(contentInfoBO.getExtra().getRelationImgList())) {
            List<String> relationImgList = contentInfoBO.getExtra().getRelationImgList();
            if (relationImgList.size() > BizConstants.DEFAULT_MAX_RELATION_IMG_SIZE) {
                log.error("ContentInfoService#updateContentDetail 更新内容详情失败 超过默认支持图片数量 contentDetailBO：【{}】", JSONObject.toJSONString(contentDetailBO));
                return false;
            }
        }
        return true;

    }

    @Override
    public List<ContentInfoBO> queryContentInfoByIdList(List<Long> contentIdList) {
        if (CollectionUtils.isEmpty(contentIdList)) {
            return Lists.newArrayList();
        }
        if (contentIdList.size() > BizConstants.DEFAULT_MAX_QUERY_CONTENT_SIZE) {
            throw new BizException(BizErrorCodeEnum.OPERATION_FAILED, "查询数量超限");
        }
        List<ContentInfoPO> contentInfoPOList = contentInfoRepository.queryContentInfoByIdList(contentIdList);
        if (CollectionUtils.isEmpty(contentInfoPOList)) {
            return Lists.newArrayList();
        }
        return contentInfoPOList.stream().map(ContentConvert::convertToContentInfoBO).collect(Collectors.toList());
    }

    @Override
    public Boolean removeContentByIdList(List<Long> contentIdList) {
        if (CollectionUtils.isEmpty(contentIdList)) {
            return true;
        }
        Boolean removed = contentInfoRepository.removeContentByIdList(contentIdList);
        if (removed) {
            for (Long contentId : contentIdList) {
                String contentDetailKey = ContentKeyBuild.buildContentDetailKey(contentId);
                redisService.del(contentDetailKey);
                LambdaEsQueryWrapper<ContentDetailEntity> wrapper = new LambdaEsQueryWrapper<>();
                wrapper.eq(ContentDetailEntity::getMysqlId, contentId);
                contentDetailEntityMapper.delete(wrapper);
            }
        }
        return removed;
    }

    @Override
    public Boolean updateContentInfoCount(ContentInfoCountBO contentInfoCountBO) {
        if (contentInfoCountBO == null || contentInfoCountBO.getContentId() == null) {
            return false;
        }
        ContentDetailDO contentDetailDO = contentInfoRepository.queryContentDetailById(contentInfoCountBO.getContentId());
        if (contentDetailDO == null) {
            log.error("ContentInfoService#updateContentInfoCont 更新内容数量信息失败，数据为空，默认不更新 contentInfoCountBO:{}", JSONObject.toJSONString(contentInfoCountBO));
            throw new BizException(BizErrorCodeEnum.OPERATION_FAILED, "内容不存在");
        }
        contentDetailDO.getContentInfo().setSeeCount(contentInfoCountBO.getSeeCount());
        contentDetailDO.getContentInfo().setLikeCount(contentInfoCountBO.getLikeCount());
        contentDetailDO.getContentInfo().setCommentCount(contentInfoCountBO.getCommentCount());
        contentDetailDO.getContentInfo().setCollectCount(contentInfoCountBO.getCollectCount());
        Boolean updated = contentInfoRepository.updateContentDetailById(contentDetailDO, true);
        if (updated) {
            String detailKey = ContentKeyBuild.buildContentDetailKey(contentInfoCountBO.getContentId());
            redisService.set8H(detailKey, JSONObject.toJSONString(contentDetailDO));

            ContentDetailEntity contentDetailEntity = new ContentDetailEntity();
            contentDetailEntity.setSeeCount(contentInfoCountBO.getSeeCount());
            contentDetailEntity.setLikeCount(contentInfoCountBO.getLikeCount());
            contentDetailEntity.setCommentCount(contentInfoCountBO.getCommentCount());
            contentDetailEntity.setCollectCount(contentInfoCountBO.getCollectCount());
            contentDetailEntity.setMysqlId(contentDetailDO.getId());
            LambdaEsQueryWrapper<ContentDetailEntity> wrapper = new LambdaEsQueryWrapper<>();
            wrapper.eq(ContentDetailEntity::getMysqlId, contentDetailDO.getId());
            contentDetailEntityMapper.updateById(contentDetailEntity);
        }
        return updated;
    }

    private void doContentStatusChange(Long contentId, ContentStatusEnum contentStatusEnum) {
        ContentStatusChangeEntity entity = new ContentStatusChangeEntity();
        entity.setContentId(contentId);
        entity.setCurrentStatus(contentStatusEnum);
        contentMqSender.sendContentStatusChange(entity, 0);
        log.info("ContentInfoService#doContentStatusChange 发送内容状态变更，发送消息到mq，entity:{}", JSONObject.toJSONString(entity));
    }
}
